#include <iostream>
#include <queue>
#include <vector>
#include <functional>
#include <memory>
#include <future>
#include "functional.hpp"
#include "worker.hpp"
#include "ring_queue.hpp"
#include "thread_pool.hpp"
#ifdef WITH_ASIO
#include "asio_thread_pool.hpp"
// #include "pool.hpp"
#endif

// static const size_t CONCURRENCY = 2;
// static const size_t REPOST_COUNT = 1000000;

// struct RepostJob
// {
//     //Heavy heavy;

//     ThreadPool* thread_pool;
// #ifdef WITH_ASIO
//     AsioThreadPool* asio_thread_pool;
// #endif

//     volatile size_t counter;
//     long long int begin_count;
//     std::promise<void>* waiter;

//     RepostJob(ThreadPool* thread_pool, std::promise<void>* waiter)
//         : thread_pool(thread_pool)
// #ifdef WITH_ASIO
//           ,
//           asio_thread_pool(0)
// #endif
//           ,
//           counter(0), waiter(waiter)
//     {
//         begin_count = std::chrono::high_resolution_clock::now()
//                           .time_since_epoch()
//                           .count();
//     }

// #ifdef WITH_ASIO
//     RepostJob(AsioThreadPool* asio_thread_pool, std::promise<void>* waiter)
//         : thread_pool(0), asio_thread_pool(asio_thread_pool), counter(0),
//           waiter(waiter)
//     {
//         begin_count = std::chrono::high_resolution_clock::now()
//                           .time_since_epoch()
//                           .count();
//     }
// #endif

//     void operator()()
//     {
//         if(++counter < REPOST_COUNT)
//         {
// #ifdef WITH_ASIO
//             if(asio_thread_pool)
//             {
//                 asio_thread_pool->post(*this);
//                 return;
//             }
// #endif
//             if(thread_pool)
//             {
//                 thread_pool->post(*this);
//                 return;
//             }
//         }
//         else
//         {
//             long long int end_count = std::chrono::high_resolution_clock::now()
//                                           .time_since_epoch()
//                                           .count();
//             std::cout << "reposted " << counter << " in "
//                       << (double)(end_count - begin_count) / (double)1000000
//                       << " ms" << std::endl;
//             waiter->set_value();
//         }
//     }
// };

// int main(int, const char* [])
// {
//     std::cout << "Benchmark job reposting" << std::endl;

//     {
//         std::cout << "***thread pool cpp***" << std::endl;

//         std::promise<void> waiters[CONCURRENCY];
//         ThreadPool thread_pool;
//         for(auto& waiter : waiters)
//         {
//             thread_pool.post(RepostJob(&thread_pool, &waiter));
//         }

//         for(auto& waiter : waiters)
//         {
//             waiter.get_future().wait();
//         }
//     }

// #ifdef WITH_ASIO
//     {
//         std::cout << "***asio thread pool***" << std::endl;

//         size_t workers_count = std::thread::hardware_concurrency();
//         if(0 == workers_count)
//         {
//             workers_count = 1;
//         }

//         AsioThreadPool asio_thread_pool(workers_count);

//         std::promise<void> waiters[CONCURRENCY];
//         for(auto& waiter : waiters)
//         {
//             asio_thread_pool.post(RepostJob(&asio_thread_pool, &waiter));
//         }

//         for(auto& waiter : waiters)
//         {
//             waiter.get_future().wait();
//         }
//     }
// #endif

//     return 0;
// }

// #include <iostream>
// #include <queue>
// #include <vector>
// #include <functional>
// #include <memory>
// #include <future>
// #include "functional.hpp"
// #include "worker.hpp"
// #include "ring_queue.hpp"
// #include "thread_pool.hpp"
// #ifdef WITH_ASIO
// // #include "asio_thread_pool.hpp"
// #include "pool.hpp"
// #endif

// static const size_t CONCURRENCY = 2;
// static const size_t REPOST_COUNT = 1000000;

// struct RepostJob
// {
//     // Heavy heavy;

//     ThreadPool *thread_pool;
// #ifdef WITH_ASIO
//     // AsioThreadPool *asio_thread_pool;
//     Pool *pool;
// #endif

//     volatile size_t counter;
//     long long int begin_count;
//     std::promise<void> *waiter;

//     RepostJob(ThreadPool *thread_pool, std::promise<void> *waiter)
//         : thread_pool(thread_pool)
// #ifdef WITH_ASIO
//           ,
//           pool(nullptr)
// #endif
//           ,
//           counter(0), waiter(waiter)
//     {
//         begin_count = std::chrono::high_resolution_clock::now()
//                           .time_since_epoch()
//                           .count();
//     }

// #ifdef WITH_ASIO
//     RepostJob(Pool *pool, std::promise<void> *waiter)
//         : thread_pool(0), pool(pool), counter(0),
//           waiter(waiter)
//     {
//         begin_count = std::chrono::high_resolution_clock::now()
//                           .time_since_epoch()
//                           .count();
//     }
// #endif

//     void operator()()
//     {
//         if (++counter < REPOST_COUNT)
//         {
// #ifdef WITH_ASIO
//             if (pool)
//             {
//                 pool->push(*this);
//                 return;
//             }
// #endif
//             if (thread_pool)
//             {
//                 thread_pool->post(*this);
//                 return;
//             }
//         }
//         else
//         {
//             long long int end_count = std::chrono::high_resolution_clock::now()
//                                           .time_since_epoch()
//                                           .count();
//             std::cout << "reposted " << counter << " in "
//                       << (double)(end_count - begin_count) / (double)1000000
//                       << " ms" << std::endl;
//             waiter->set_value();
//         }
//     }
// };

// int main()
// {
//     std::cout << "Benchmark job reposting" << std::endl;

//     {
//         std::cout << "***thread pool cpp***" << std::endl;

//         std::promise<void> waiters[CONCURRENCY];
//         ThreadPool thread_pool;
//         for (auto &waiter : waiters)
//         {
//             thread_pool.post(RepostJob(&thread_pool, &waiter));
//         }

//         for (auto &waiter : waiters)
//         {
//             waiter.get_future().wait();
//         }
//     }

// #ifdef WITH_ASIO
//     {
//         std::cout << "*** pool***" << std::endl;

//         size_t workers_count = std::thread::hardware_concurrency();
//         if (0 == workers_count)
//         {
//             workers_count = 1;
//         }

//         Pool pool(workers_count);

//         std::promise<void> waiters[CONCURRENCY];
//         for (auto &waiter : waiters)
//         {
//             pool.push(RepostJob(&pool, &waiter));
//         }

//         for (auto &waiter : waiters)
//         {
//             waiter.get_future().wait();
//         }
//     }
// #endif
// }

// using task_t = std::function<void()>;
// std::vector<std::shared_ptr<Worker<task_t, RingQueue>>> workers;
// workers.emplace_back(std::make_shared<Worker<task_t, RingQueue>>(1024));
// workers.emplace_back(std::make_shared<Worker<task_t, RingQueue>>(1024));

// workers[0]->start(0, workers[1].get());
// workers[1]->start(1, workers[0].get());

// for(int i = 0; i < 1000; i++)
// {
//     // std::cout << i << std::endl;
//     workers[0]->post(std::bind(&Add, i, i + 1));
//     workers[1]->post(std::bind(&Add, i + 100, i + 101));
// }
// // std::this_thread::sleep_for(std::chrono::milliseconds(3000));

// workers[0]->stop();
// workers[1]->stop();

// ThreadPool tp;

// for(int i = 0; i < 12345; i++)
// {
//     tp.post(Functional<void()>(std::bind(&Add, i, i + 100)));
// }

// std::this_thread::sleep_for(std::chrono::milliseconds(3000));
// std::cout << arr.size() << std::endl;
// // std::deque<
// return 0;

std::mutex mtx;
std::vector<std::string> arr;

class A
{
public:
    void Add(const std::string& qname)
    {
        std::unique_lock<std::mutex> ul(mtx);
        // std::cout << qname << std::endl;
        // std::cout << arr.size()
        arr.push_back(qname);
    }
};

int main()
{
    using task_t = std::function<void()>;
    std::vector<std::shared_ptr<Worker<task_t, RingQueue>>> workers;
    workers.emplace_back(std::make_shared<Worker<task_t, RingQueue>>(8192));
    workers.emplace_back(std::make_shared<Worker<task_t, RingQueue>>(8192));

    workers[0]->start(0, workers[1].get());
    workers[1]->start(1, workers[0].get());

    A a;
    // std::string s1 = std::to_string(123);
    // std::string s2 = std::to_string(100);
    
    std::string&& s("111111");


    std::thread t1([&](){
        for (int i = 0; i < 1000; i++)
        {
            // std::cout << i << std::endl;
            workers[0]->post(std::bind(&A::Add, &a, s));
            // workers[1]->post(std::bind(&A::Add, &a, s1, s2));
        }
    });

    std::thread t2([&](){
        for (int i = 0; i < 1000; i++)
        {
            // std::cout << i << std::endl;
            workers[1]->post(std::bind(&A::Add, &a, s));
            // workers[1]->post(std::bind(&A::Add, &a, s1, s2));
        }
    });



    std::this_thread::sleep_for(std::chrono::milliseconds(10000));

    workers[0]->stop();
    workers[1]->stop();

    t1.join();
    t2.join();

    std::cout << arr.size() << std::endl;
    // std::deque<
    return 0;
}